// *****************************************************************************
// *****************************************************************************
// Copyright 2012 - 2013, Cadence Design Systems
//
// This  file  is  part  of  the  Cadence  LEF/DEF  Open   Source
// Distribution,  Product Version 5.8.
//
// Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
//    implied. See the License for the specific language governing
//    permissions and limitations under the License.
//
// For updates, support, or to become part of the LEF/DEF Community,
// check www.openeda.org for details.
//
//  $Author: dell $
//  $Revision: #1 $
//  $Date: 2020/09/29 $
//  $State:  $
// *****************************************************************************
// *****************************************************************************

#include "lefiArray.hpp"

#include <cstdlib>
#include <cstring>

#include "lefiDebug.hpp"
#include "lefiMisc.hpp"
#include "lex.h"

BEGIN_LEF_PARSER_NAMESPACE
// *****************************************************************************
// lefiArrayFloorPlan
// *****************************************************************************

void lefiArrayFloorPlan::Init(const char* name)
{
  int len = strlen(name) + 1;
  name_ = (char*) lefMalloc(len);
  strcpy(name_, CASE(name));
  numPatterns_ = 0;
  patternsAllocated_ = 2;
  types_ = (char**) lefMalloc(sizeof(char*) * 2);
  patterns_ = (lefiSitePattern**) lefMalloc(sizeof(lefiSitePattern*) * 2);
}

void lefiArrayFloorPlan::Destroy()
{
  lefiSitePattern* s;
  int i;
  for (i = 0; i < numPatterns_; i++) {
    s = patterns_[i];
    s->Destroy();
    lefFree(s);
    lefFree(types_[i]);
  }
  lefFree(types_);
  lefFree(patterns_);
  lefFree(name_);
}

void lefiArrayFloorPlan::addSitePattern(const char* typ, lefiSitePattern* s)
{
  int len = strlen(typ) + 1;
  if (numPatterns_ == patternsAllocated_) {
    int i;
    int lim;
    char** nc;
    lefiSitePattern** np;

    if (patternsAllocated_ == 0) {
      lim = patternsAllocated_ = 2;
    } else {
      lim = patternsAllocated_ = patternsAllocated_ * 2;
    }
    nc = (char**) lefMalloc(sizeof(char*) * lim);
    np = (lefiSitePattern**) lefMalloc(sizeof(lefiSitePattern*) * lim);
    lim /= 2;
    for (i = 0; i < lim; i++) {
      nc[i] = types_[i];
      np[i] = patterns_[i];
    }
    lefFree(types_);
    lefFree(patterns_);
    types_ = nc;
    patterns_ = np;
  }
  types_[numPatterns_] = (char*) lefMalloc(len);
  strcpy(types_[numPatterns_], typ);
  patterns_[numPatterns_] = s;
  numPatterns_ += 1;
}

int lefiArrayFloorPlan::numPatterns() const
{
  return numPatterns_;
}

lefiSitePattern* lefiArrayFloorPlan::pattern(int index) const
{
  return patterns_[index];
}

char* lefiArrayFloorPlan::typ(int index) const
{
  return types_[index];
}

const char* lefiArrayFloorPlan::name() const
{
  return name_;
}

// *****************************************************************************
// lefiArray
// *****************************************************************************
lefiArray::lefiArray()
{
  Init();
}

void lefiArray::Init()
{
  nameSize_ = 16;
  name_ = (char*) lefMalloc(16);

  numPatterns_ = 0;
  patternsAllocated_ = 0;
  bump((void***) (&(pattern_)), numPatterns_, &(patternsAllocated_));

  numCan_ = 0;
  canAllocated_ = 0;
  bump((void***) (&(canPlace_)), numCan_, &(canAllocated_));

  numCannot_ = 0;
  cannotAllocated_ = 0;
  bump((void***) (&(cannotOccupy_)), numCannot_, &(cannotAllocated_));

  numTracks_ = 0;
  tracksAllocated_ = 0;
  bump((void***) (&(track_)), numTracks_, &(tracksAllocated_));

  numG_ = 0;
  gAllocated_ = 0;
  bump((void***) (&(gcell_)), numG_, &(gAllocated_));

  numDefault_ = 0;
  defaultAllocated_ = 4;
  minPins_ = (int*) lefMalloc(sizeof(int) * 4);
  caps_ = (double*) lefMalloc(sizeof(double) * 4);

  floorPlansAllocated_ = 0;
  numFloorPlans_ = 0;
  bump((void***) (&(floors_)), numFloorPlans_, &(floorPlansAllocated_));
}

void lefiArray::Destroy()
{
  clear();

  lefFree(name_);
  lefFree(caps_);
  lefFree(minPins_);
  lefFree(floors_);
  lefFree(track_);
  lefFree(gcell_);
  lefFree(cannotOccupy_);
  lefFree(canPlace_);
  lefFree(pattern_);
}

lefiArray::~lefiArray()
{
  Destroy();
}

void lefiArray::addSitePattern(lefiSitePattern* s)
{
  /*
    if (numPatterns_ == patternsAllocated_)
      bump((void***)(&(pattern_)), numPatterns_,
      &(patternsAllocated_));
  */
  if (numPatterns_ == patternsAllocated_) {
    lefiSitePattern** tpattern;
    int i;

    if (patternsAllocated_ == 0) {
      patternsAllocated_ = 2;
    } else {
      patternsAllocated_ = patternsAllocated_ * 2;
    }
    tpattern = (lefiSitePattern**) lefMalloc(sizeof(lefiSitePattern*)
                                             * patternsAllocated_);
    for (i = 0; i < numPatterns_; i++) {
      tpattern[i] = pattern_[i];
    }
    if (pattern_) {
      lefFree(pattern_);
    }
    pattern_ = tpattern;
    /*
        bump((void***)(&(pattern_)), numPatterns_,
        &(patternsAllocated_));
    */
  }

  pattern_[numPatterns_] = s;
  numPatterns_ += 1;
}

void lefiArray::setName(const char* name)
{
  int len = strlen(name) + 1;
  if (len > nameSize_) {
    lefFree(name_);
    name_ = (char*) lefMalloc(len);
    nameSize_ = len;
  }
  strcpy(name_, CASE(name));
}

void lefiArray::setTableSize(int tsize)
{
  tableSize_ = tsize;
  hasDefault_ = 1;
}

void lefiArray::addDefaultCap(int minPins, double cap)
{
  if (numDefault_ == defaultAllocated_) {
    int i;
    int lim;
    double* nc;
    int* np;

    if (defaultAllocated_ == 0) {
      lim = defaultAllocated_ = 2;
    } else {
      lim = defaultAllocated_ * 2;
    }
    defaultAllocated_ = lim;
    nc = (double*) lefMalloc(sizeof(double) * lim);
    np = (int*) lefMalloc(sizeof(int) * lim);
    lim /= 2;
    for (i = 0; i < lim; i++) {
      nc[i] = caps_[i];
      np[i] = minPins_[i];
    }
    lefFree(caps_);
    lefFree(minPins_);
    caps_ = nc;
    minPins_ = np;
  }
  caps_[numDefault_] = cap;
  minPins_[numDefault_] = minPins;
  numDefault_ += 1;
}

void lefiArray::addCanPlace(lefiSitePattern* s)
{
  if (numCan_ == canAllocated_) {
    lefiSitePattern** cplace;
    int i;

    if (canAllocated_ == 0) {
      canAllocated_ = 2;
    } else {
      canAllocated_ = canAllocated_ * 2;
    }
    cplace = (lefiSitePattern**) lefMalloc(sizeof(lefiSitePattern*)
                                           * canAllocated_);
    for (i = 0; i < numCan_; i++) {
      cplace[i] = canPlace_[i];
    }
    if (canPlace_) {
      lefFree(canPlace_);
    }
    canPlace_ = cplace;
  }
  /*
      bump((void***)(&(canPlace_)), numCan_, &(canAllocated_));
  */
  canPlace_[numCan_] = s;
  numCan_ += 1;
}

void lefiArray::addCannotOccupy(lefiSitePattern* s)
{
  if (numCannot_ == cannotAllocated_) {
    lefiSitePattern** cnplace;
    int i;

    if (cannotAllocated_ == 0) {
      cannotAllocated_ = 2;
    } else {
      cannotAllocated_ = cannotAllocated_ * 2;
    }
    cnplace = (lefiSitePattern**) lefMalloc(sizeof(lefiSitePattern*)
                                            * cannotAllocated_);
    for (i = 0; i < numCannot_; i++) {
      cnplace[i] = cannotOccupy_[i];
    }
    if (cannotOccupy_) {
      lefFree(cannotOccupy_);
    }
    cannotOccupy_ = cnplace;
  }
  /*
    if (numCannot_ == cannotAllocated_)
      bump((void***)(&(cannotOccupy_)), numCannot_,
      &(cannotAllocated_));
  */
  cannotOccupy_[numCannot_] = s;
  numCannot_ += 1;
}

void lefiArray::addTrack(lefiTrackPattern* t)
{
  if (numTracks_ == tracksAllocated_) {
    lefiTrackPattern** tracks;
    int i;

    if (tracksAllocated_ == 0) {
      tracksAllocated_ = 2;
    } else {
      tracksAllocated_ = tracksAllocated_ * 2;
    }
    tracks = (lefiTrackPattern**) lefMalloc(sizeof(lefiTrackPattern*)
                                            * tracksAllocated_);
    for (i = 0; i < numTracks_; i++) {
      tracks[i] = track_[i];
    }
    if (track_) {
      lefFree(track_);
    }
    track_ = tracks;
  }
  /*
    if (numTracks_ == tracksAllocated_)
      bump((void***)(&(track_)), numTracks_, &(tracksAllocated_));
  */
  track_[numTracks_] = t;
  numTracks_ += 1;
}

void lefiArray::addGcell(lefiGcellPattern* g)
{
  if (numG_ == gAllocated_) {
    lefiGcellPattern** cells;
    int i;

    if (gAllocated_ == 0) {
      gAllocated_ = 2;
    } else {
      gAllocated_ = gAllocated_ * 2;
    }
    cells = (lefiGcellPattern**) lefMalloc(sizeof(lefiGcellPattern*)
                                           * gAllocated_);
    for (i = 0; i < numG_; i++) {
      cells[i] = gcell_[i];
    }
    if (gcell_) {
      lefFree(gcell_);
    }
    gcell_ = cells;
  }
  /*
    if (numG_ == gAllocated_)
      bump((void***)(&(gcell_)), numG_, &(gAllocated_));
  */
  gcell_[numG_] = g;
  numG_ += 1;
}

void lefiArray::addFloorPlan(const char* name)
{
  lefiArrayFloorPlan* f;
  if (numFloorPlans_ == floorPlansAllocated_) {
    int i;
    lefiArrayFloorPlan** tf;

    if (floorPlansAllocated_ == 0) {
      floorPlansAllocated_ = 2;
    } else {
      floorPlansAllocated_ = floorPlansAllocated_ * 2;
    }
    tf = (lefiArrayFloorPlan**) lefMalloc(sizeof(lefiArrayFloorPlan*)
                                          * floorPlansAllocated_);
    for (i = 0; i < numFloorPlans_; i++) {
      tf[i] = floors_[i];
    }
    if (floors_) {
      lefFree(floors_);
    }
    floors_ = tf;
  }
  /*
    if (numFloorPlans_ == floorPlansAllocated_) {
      bump((void***)(&(floors_)), numFloorPlans_,
      &(floorPlansAllocated_));
    }
  */
  f = (lefiArrayFloorPlan*) lefMalloc(sizeof(lefiArrayFloorPlan));
  f->Init(name);
  floors_[numFloorPlans_] = f;
  numFloorPlans_ += 1;
}

void lefiArray::addSiteToFloorPlan(const char* typ, lefiSitePattern* s)
{
  lefiArrayFloorPlan* f = floors_[numFloorPlans_ - 1];
  f->addSitePattern(typ, s);
}

void lefiArray::bump(void*** arr, int used, int* allocated)
{
  int size = *allocated * 2;
  int i;
  void** newa;
  if (size == 0) {
    size = 2;
  }
  newa = (void**) lefMalloc(sizeof(void*) * size);

  for (i = 0; i < used; i++) {
    newa[i] = (*arr)[i];
  }

  if (*arr) {
    lefFree(*arr);
  }
  *allocated = size;
  *arr = newa;
}

void lefiArray::clear()
{
  int i;
  lefiSitePattern* p;
  lefiGcellPattern* g;
  lefiTrackPattern* t;
  lefiArrayFloorPlan* f;

  for (i = 0; i < numPatterns_; i++) {
    p = pattern_[i];
    p->Destroy();
    lefFree(p);
  }
  numPatterns_ = 0;

  for (i = 0; i < numCan_; i++) {
    p = canPlace_[i];
    p->Destroy();
    lefFree(p);
  }
  numCan_ = 0;

  for (i = 0; i < numCannot_; i++) {
    p = cannotOccupy_[i];
    p->Destroy();
    lefFree(p);
  }
  numCannot_ = 0;

  for (i = 0; i < numTracks_; i++) {
    t = track_[i];
    t->Destroy();
    lefFree(t);
  }
  numTracks_ = 0;

  for (i = 0; i < numG_; i++) {
    g = gcell_[i];
    g->Destroy();
    lefFree(g);
  }
  numG_ = 0;

  hasDefault_ = 0;
  tableSize_ = 0;
  numDefault_ = 0;

  for (i = 0; i < numFloorPlans_; i++) {
    f = floors_[i];
    f->Destroy();
    lefFree(f);
  }
  numFloorPlans_ = 0;
}

int lefiArray::numSitePattern() const
{
  return numPatterns_;
}

int lefiArray::numCanPlace() const
{
  return numCan_;
}

int lefiArray::numCannotOccupy() const
{
  return numCannot_;
}

int lefiArray::numTrack() const
{
  return numTracks_;
}

int lefiArray::numGcell() const
{
  return numG_;
}

int lefiArray::hasDefaultCap() const
{
  return hasDefault_;
}

const char* lefiArray::name() const
{
  return name_;
}

lefiSitePattern* lefiArray::sitePattern(int index) const
{
  return pattern_[index];
}

lefiSitePattern* lefiArray::canPlace(int index) const
{
  return canPlace_[index];
}

lefiSitePattern* lefiArray::cannotOccupy(int index) const
{
  return cannotOccupy_[index];
}

lefiTrackPattern* lefiArray::track(int index) const
{
  return track_[index];
}

lefiGcellPattern* lefiArray::gcell(int index) const
{
  return gcell_[index];
}

int lefiArray::tableSize() const
{
  return tableSize_;
}

int lefiArray::numDefaultCaps() const
{
  return numDefault_;
}

int lefiArray::defaultCapMinPins(int index) const
{
  return minPins_[index];
}

double lefiArray::defaultCap(int index) const
{
  return caps_[index];
}

int lefiArray::numFloorPlans() const
{
  return numFloorPlans_;
}

const char* lefiArray::floorPlanName(int index) const
{
  const lefiArrayFloorPlan* f = floors_[index];
  return f->name();
}

int lefiArray::numSites(int index) const
{
  const lefiArrayFloorPlan* f = floors_[index];
  return f->numPatterns();
}

const char* lefiArray::siteType(int index, int j) const
{
  const lefiArrayFloorPlan* f = floors_[index];
  return f->typ(j);
}

lefiSitePattern* lefiArray::site(int index, int j) const
{
  const lefiArrayFloorPlan* f = floors_[index];
  return f->pattern(j);
}

void lefiArray::print(FILE* f) const
{
  fprintf(f, "ARRAY %s\n", name());
}

END_LEF_PARSER_NAMESPACE
